package lanQiaoBei.搜索与图论.二分图;

import java.io.*;
import java.math.*;
import java.util.*;

/*匈牙利算法(求二分图的最大匹配)
*给定一个二分图，其中左半部包含 n1 个点（编号 1∼n1），右半部包含 n2 个点（编号 1∼n2），二分图共包含 m 条边。

数据保证任意一条边的两个端点都不可能在同一部分中。

请你求出二分图的最大匹配数。

二分图的匹配：给定一个二分图 G，在 G 的一个子图 M 中，M 的边集 {E} 中的任意两条边都不依附于同一个顶点，则称 M 是一个匹配。
二分图的最大匹配：所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配，其边数即为最大匹配数。

输入格式
第一行包含三个整数 n1、 n2 和 m。

接下来 m 行，每行包含两个整数 u 和 v，表示左半部点集中的点 u 和右半部点集中的点 v 之间存在一条边。

输出格式
输出一个整数，表示二分图的最大匹配数。

数据范围
1≤n1,n2≤500,
1≤u≤n1,
1≤v≤n2,
1≤m≤105

输入样例：
2 2 3
1 1
2 1
2 2
1 2
输出样例：
2
* */
public class P2 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    final static int N = 510, M = 100010;
    static int h[] = new int[N], e[] = new int[M], ne[] = new int[M], match[] = new int[N], idx, n1, n2, m;
    static boolean st[] = new boolean[N];

    static void add(int a, int b) {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }

    static void scan() throws Exception {
        String[] ss = br.readLine().split(" ");
        n1 = Integer.parseInt(ss[0]);
        n2 = Integer.parseInt(ss[1]);
        m = Integer.parseInt(ss[2]);
        Arrays.fill(h, -1);
        while (m-- > 0) {
            ss = br.readLine().split(" ");
            int a = Integer.parseInt(ss[0]), b = Integer.parseInt(ss[1]);
            add(a, b);
        }
    }

    static boolean find(int x) {
        for (int i = h[x]; i != -1; i = ne[i]) {
            int j = e[i];
            if (!st[j]) {
                st[j] = true;
                if (match[j] == 0 || find(match[j])) {
                    match[j] = x;
                    return true;
                }
            }
        }
        return false;
    }

    public static void main(String[] args) throws Exception {
        scan();
        int res = 0;
        for (int i = 1; i <= n1; i++) {
            Arrays.fill(st, false);
            if (find(i)) res++;
        }
        System.out.println(res);
    }
}
